package Thread;
//自主实现定时器原理

import java.util.PriorityQueue;

//1.实现MyTimerTask类用来表示每一个定时器任务
class MyTimerTask implements Comparable<MyTimerTask>{
    private Runnable runnable;//表示要完成的任务
    private long time;//表示执行任务的时间
    public MyTimerTask(Runnable runnable,long delay){
        this.runnable = runnable;
        this.time = System.currentTimeMillis() + delay;
    }

    public Runnable getRunnable() {
        return runnable;
    }

    public long getTime() {
        return time;
    }

    @Override
    public int compareTo(MyTimerTask o) {
        return (int)(this.time - o.time);
    }
}
//2.实现MyTimer类用于组织各定时器任务
class MyTimer{
    //创建优先级队列（堆）用来存放所有的定时器任务
    private PriorityQueue<MyTimerTask> priorityQueue = new PriorityQueue<>();
    //将每个定时器任务存放到priorityQueue里面
    public void schedule(Runnable runnable, long time){
        synchronized (this){
            MyTimerTask myTimerTask = new MyTimerTask(runnable,time);
            priorityQueue.offer(myTimerTask);
            this.notify();
        }
    }
    //使用方法实现：使用一个线程来遍历各个定时器任务，看是否到时间开始执行任务，到点了之后开始执行定时器的runnable任务
    public MyTimer(){
        Thread t = new Thread(()->{
            while(true){
                try {
                    synchronized (this){
                        while (priorityQueue.isEmpty()){
                            //如果优先级队列里面没有定时器任务，则等待，进入阻塞状态，直到有定时器任务来到
                            try {
                                this.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        //优先级队列不为空
                        MyTimerTask task = priorityQueue.peek();
                        long curTime = System.currentTimeMillis();
                        //如果当前到堆顶元素执行的时间了，则执行,同时将堆顶元素弹出
                        if (curTime >= task.getTime()){
                            task.getRunnable().run();
                            priorityQueue.poll();
                        }else {
                            //还没到时间
                            this.wait(task.getTime() - curTime);
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        });
        t.start();
    }
}

public class Demo21 {
    public static void main(String[] args) {
        //创建定时器并安排任务
        MyTimer timer = new MyTimer();
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello3");
            }
        },3000);
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello2");
            }
        },2000);
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello1");
            }
        },1000);
        System.out.println("程序开始执行");
    }
}
